/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Model;

import Componenten.Coordinaat;
import Componenten.LocalTypes;
import java.util.ArrayList;
import java.util.Set;

/**
 * Klasse die het Sokoban speelbord met speelvakken representeert.
 * @author Bram Slob en Roderick van Seijen
 */
public class Bord implements LocalTypes {
    
    private int levelCode;
    private Modus speelModus;
    private int stappen;
    private Vak[][] vakMatrix; 
    private Element speler;
    private ArrayList<Vak> eindvakken;
    private boolean levelGehaald;
    private boolean spelUitgespeeld;
    private SpelVariant spelVariant;
    
    /**
     * Constructor voor Bord
     */
    public Bord(){
        speelModus = Modus.VOLWASSENE;
        spelVariant = SpelVariant.STANDAARD;
    }
    
    /**
     *  Laad de betreffende level en zet relevante variabelen naar hun startwaarde.
     * 
     * @param lvl   levelcode
     */
    public void startLevel(int lvl){
        stappen = 0;
        levelCode = lvl;
        levelGehaald = false;
        spelUitgespeeld = false;
        
        String level = Level.getLevel(lvl);
        int kolommen = Level.getAantalKolommen();
        int rijen = Level.getAantalRijen();
        
        vakMatrix = new Vak[rijen][kolommen];
        eindvakken = new ArrayList();
        for (int y = 0; y < rijen; ++y)
        {
            for (int x = 0; x < kolommen; ++x)
            {
                vakMatrix[y][x] = new Vak(new Coordinaat(x,y));
            }
        }
        
        int rij = 0;
        int kolom = 0;
        
        Vak vk;
        for(int i = 0; i < level.length(); i++){
            char dit = level.charAt(i);
            
            if (dit == '\n'){ 
                vk = null;
            } else {
                vk = vakMatrix[rij][kolom];
            }
            switch(dit){
                case '\n':
                    rij += 1;
                    kolom = 0;
                    break;
                    
                case '#': // muur
                    vk.setVakType(VakType.NORMAAL);
                    vk.setElement(new Element(ElementType.MUUR, vk));
                    break;
                case ' ': // leeg vak
                    vk.setVakType(VakType.NORMAAL);
                    break;
                case '.': // muur
                    vk.setVakType(VakType.EIND);
                    eindvakken.add(vk);
                    break;
                case '@': // speler op normaal vak
                    vk.setVakType(VakType.NORMAAL);
                    vk.setElement(new Element(ElementType.SPELER, vk));
                    speler = vk.getElement();
                    break;
                case '+': // speler op eindvak
                    vk.setVakType(VakType.EIND);
                    vk.setElement(new Element(ElementType.SPELER, vk));
                    speler = vk.getElement();
                    eindvakken.add(vk);
                    break;
                case '$': // lege doos
                    vk.setVakType(VakType.NORMAAL);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.LEGE_DOOS, vk));
                    } else {
                        vk.setElement(new Element(ElementType.DOOS, vk));
                    }
                    break;
                case 'x': // volle doos
                    vk.setVakType(VakType.NORMAAL);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.VOLLE_DOOS, vk));
                    } else {
                        vk.setElement(new Element(ElementType.DOOS, vk));
                    }
                    break;
                case 'w': // hulpstuk 
                    vk.setVakType(VakType.NORMAAL);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.HULPSTUK, vk));
                    }
                    break;
                case '*': // lege doos op eindvlak
                    vk.setVakType(VakType.EIND);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.LEGE_DOOS, vk));
                    } else {
                        vk.setElement(new Element(ElementType.DOOS, vk));
                    }
                    eindvakken.add(vk);
                    break;
                case 'z': // hulpstuk op eindvlak
                    vk.setVakType(VakType.EIND);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.HULPSTUK, vk));
                    }
                    eindvakken.add(vk);
                    break;
                case 'y': // volle doos op eindvlak
                    vk.setVakType(VakType.EIND);
                    if (spelVariant == SpelVariant.UITGEBREID){
                        vk.setElement(new Element(ElementType.VOLLE_DOOS, vk));
                    } else {
                        vk.setElement(new Element(ElementType.DOOS, vk));
                    }
                    eindvakken.add(vk);
                    break;
                case '_': // buitenvak
                    vk.setVakType(VakType.BUITEN);
                    break;
            }
            if(dit != '\n'){
                if(rij != 0){
                    vk.setBuurvak(Richting.NOORD, vakMatrix[rij -1][kolom]);
                }
                if(rij != rijen - 1){
                    vk.setBuurvak(Richting.ZUID, vakMatrix[rij + 1][kolom]);
                }
                if(kolom != 0){
                    vk.setBuurvak(Richting.WEST, vakMatrix[rij][kolom - 1]);
                }
                if(kolom != kolommen - 1){
                    vk.setBuurvak(Richting.OOST, vakMatrix[rij][kolom + 1]);
                }
                
                kolom += 1;  
            }

        }
    }
    
    /**
     * @return boolean waarde die aangeeft of de huidige level gehaald is
     */
    public boolean isLevelGehaald(){
        return levelGehaald;
    }
    
    /**
     * @return boolean waarde die aangeeft of het spel is uitgespeeld
     */
    public boolean isSpelUitgespeeld(){
        return spelUitgespeeld;
    }
    
    /**
     * Start de eerste level in het spel
     */
    public void startSpel(){
        System.out.println("start");
        startLevel(1);
    }
    
    /**
     * Herstart de huidige level
     */
    public void herstartLevel(){
        startLevel(levelCode);
    }
    
     /**
     * Start de volgende level in het spel
     */
    public void startVolgendeLevel(){
        startLevel(levelCode + 1); 
    }

    /**
     * @return Het levelnummer
     */
    public int getLevelCode() {
        return levelCode;
    }
    
    /**
     * @return Een 2-dimensionale array van de vakken in het spel
     */
    public Vak[][] getVakMatrix(){
        return vakMatrix;
    }
    
    /**
     * @return De modus waarin het spel zich bevindt (kind of volwassene)
     */
    public Modus getSpeelModus(){
        return speelModus;
    }
    
    /**
     * @param m  De modus waar het spel op gezet wordt (kind of volwassene)
     */
    public void setSpeelModus(Modus m){
        speelModus = m;
    }
    
    /**
     * @return De modus waarin het spel zich bevindt (kind of volwassene)
     */
    public SpelVariant getSpelVariant(){
        return spelVariant;
    }
    
    /**
     * @param m  De modus waar het spel op gezet wordt (kind of volwassene)
     */
    public void setSpelVariant(SpelVariant s){
        spelVariant = s;
    }
    
    /**
     * @return stappen  Het aantal vakken dat de speler verplaatst is sinds het begin van het level.
     */
    public int getStappen(){
        return stappen;
    }
    
    /**
     * @return  aantal eindvakken in het level
     */
    public int getAantalEindvakken()
    {
        return eindvakken.size();
    }
    
    /**
     * Vraag de speler om naar het buurvak in de aangegeven richting te verplaatsen. 
     * @param r  Richting van de gevraagde beweging
     * @return Set met alle vakken die een verandering hebben ondervonden door de beweging (van de speler en eventuele aangrenzende dozen. 
     *         Lege Set indien er geen beweging mogelijk is.
     */ 
    public Set<Vak> beweegSpeler(Richting r){
        
        Set<Vak> vakken = speler.beweeg(r, speelModus);  
        if (!vakken.isEmpty() && !levelGehaald) {
            stappen += 1;
        }
        return vakken;
    }
    
    /**
     * Check hoeveel eindvakken bezet zijn door dozen en zet levelGehaald op true als alle eindvakken bezet zijn.
     * @return aantal bezette eindvakken
     */
    public int checkBezetteEindvakken()
    {
        int aantal = 0;
        ElementType eindType = null;
        if (spelVariant == SpelVariant.UITGEBREID){ 
            eindType = ElementType.VOLLE_DOOS;
        } else {
            eindType = ElementType.DOOS;
        }
        for (Vak vak: eindvakken){
            if (vak.getElement() != null && vak.getElement().getElementType() == eindType) {
                ++aantal;
            }
        }
        if (aantal == eindvakken.size()){
            levelGehaald = true;
            if (levelCode == Level.getAantalLevels()){
                spelUitgespeeld = true;
            }
            int highscore = Level.getHighscore(levelCode, speelModus, spelVariant);
            if (highscore == 0 || stappen < highscore){
                Level.setHighscore(levelCode, speelModus, spelVariant, stappen);
            }
        }
        return aantal;
    }
     
}
